// 状态
// 左走 右走 跳跃 攻击 静止
const enum State{
    left, right, jump, atttack, idle, injured,
};

const {ccclass, property} = cc._decorator;

@ccclass
export default class Player extends cc.Component {


    @property(cc.Node)
    canvas: cc.Node = null;



    @property({displayName: "死亡后隐藏的UI", tooltip: "死亡后隐藏的UI", type: cc.Node})
    UI: cc.Node[] = [];

    @property({displayName: "死亡后的复活界面", tooltip: "死亡后的复活界面", type: cc.Node})
    UI_death: cc.Node = null;

    @property({displayName: "复活按钮", tooltip: "复活按钮", type: cc.Node})
    re_btn: cc.Node = null;

    @property({displayName: "死亡后隐藏的技能按钮", tooltip: "死亡后隐藏的技能按钮", type: cc.Button})
    UI_skill_btn: cc.Button[] = [];




    @property({displayName: "紫色字体", tooltip: "紫色字体", type: cc.Font})
    purple_typeface: cc.Font = null;


    @property({displayName: "角色", tooltip: "角色", type: sp.Skeleton})
    player: sp.Skeleton = null;




    @property({displayName: "左走按钮", tooltip: "左走按钮", type: cc.Node})
    left_walk_btn: cc.Node = null;

    @property({displayName: "右走按钮", tooltip: "右走按钮", type: cc.Node})
    right_walk_btn: cc.Node = null;

    @property({displayName: "攻击按钮", tooltip: "攻击按钮", type: cc.Node})
    attack_btn: cc.Node = null;

    @property({displayName: "跳跃按钮", tooltip: "跳跃按钮", type: cc.Node})
    jump_btn: cc.Node = null;

    @property({displayName: "左攻击范围", tooltip: "左攻击范围", type: cc.Node})
    attack_left: cc.Node = null;

    @property({displayName: "右攻击范围", tooltip: "右攻击范围", type: cc.Node})
    attack_right: cc.Node = null;





    @property({displayName: "显示生命值的文字", tooltip: "显示生命值的文字", type: cc.Label})
    HP_lb: cc.Label = null;

    @property({displayName: "显示蓝的文字", tooltip: "显示蓝的文字", type: cc.Label})
    MP_lb: cc.Label = null;

    @property({displayName: "显示经验值的文字", tooltip: "显示经验值的文字", type: cc.Label})
    EXP_lb: cc.Label = null;

    @property({displayName: "显示等级的文字", tooltip: "显示等级的文字", type: cc.Label})
    LV_lb: cc.Label = null;




    @property({displayName: "生命值进度条", tooltip: "生命值进度条", type: cc.Sprite})
    HP_sp: cc.Sprite = null;

    @property({displayName: "蓝进度条", tooltip: "蓝进度条", type: cc.Sprite})
    MP_sp: cc.Sprite = null;

    @property({displayName: "经验值进度条", tooltip: "经验值进度条", type: cc.Sprite})
    EXP_sp: cc.Sprite = null;




    @property({displayName: "行走速度", tooltip: "行走速度", type: cc.Float})
    walk_speed: number = 200;

    @property({displayName: "跳跃高度", tooltip: "跳跃高度", type: cc.Float})
    jump_height: number = 200;

    @property({displayName: "跳跃后禁用几秒按钮", tooltip: "跳跃后禁用几秒按钮", type: cc.Float})
    jump_time: number = 1.6;

    @property({displayName: "攻击后禁用几秒按钮", tooltip: "攻击后禁用几秒按钮", type: cc.Float})
    attack_time: number = 0.7;

    @property({displayName: "攻击范围打开后几秒关闭", tooltip: "攻击范围打开后几秒关闭", type: cc.Float})
    attack_range_time: number = 0.2;



    // 是否是第一次执行update
    is_first_update: boolean = true;


    is_jump_OK: boolean = true;// 是否可以跳跃
    is_attack_OK: boolean = true;// 是否可以攻击


    state = State.idle;// 状态，默认为静止


    //攻击的数字，根据这个数字来决定播放哪个攻击动画
    attack_num: number = 1;







    // 攻击力提高倍率
    ATK_promote: number = 1;
    // 基本攻击力
    ATK_num: number = 0;


    // 防御力提高倍率
    AC_promote: number = 1;
    // 基本防御力
    AC_num: number = 0;


    // 基本血量
    HP_num: number = 0

    // 基本魔法
    MP_num: number = 0;

    // 基本暴击率
    CRI_num: number = 0;




    LV: number = 1;// 等级
    full_HP: number = 500;// 生命值
    full_MP: number = 500;// 蓝
    full_EXP: number = 500;// 经验值

    cur_HP: number = 500;// 生命值
    cur_MP: number = 500;// 蓝
    cur_EXP: number = 500;// 经验值





    // 攻击力
    ATK: number = 0;

    // 防御力
    AC: number = 2;

    // 暴击率   需要加百分号
    CRI: number = 55; 



    user_data = null;




    onLoad () {
        // 给左走按钮绑定事件
        this.left_walk_btn.on(cc.Node.EventType.TOUCH_START, this.left_walk, this);
        this.left_walk_btn.on(cc.Node.EventType.TOUCH_END, this.idle_walk, this);
        this.left_walk_btn.on(cc.Node.EventType.TOUCH_CANCEL, this.idle_walk, this);

        // 给右走按钮绑定事件
        this.right_walk_btn.on(cc.Node.EventType.TOUCH_START, this.right_walk, this);
        this.right_walk_btn.on(cc.Node.EventType.TOUCH_END, this.idle_walk, this);
        this.right_walk_btn.on(cc.Node.EventType.TOUCH_CANCEL, this.idle_walk, this);

        // 给跳跃和攻击按钮绑定事件
        this.attack_btn.on(cc.Node.EventType.TOUCH_START, this.attack, this);
        // this.jump_btn.on(cc.Node.EventType.TOUCH_START, this.jump, this);


        // 获取用户数据
        this.user_data = JSON.parse(cc.sys.localStorage.getItem("user_data"));


       
        // 设置等级和经验值
        this.LV = Number(this.user_data.LV);
        this.cur_EXP = Number(this.user_data.EXP);

        
        // 满的经验值是等级 * 1500
        this.full_EXP = this.LV * 1500;



        // 开始时不是攻击的
        this.attack_left.active = false;
        this.attack_right.active = false;





        /*
        以下代码为各种属性普通值和倍率值的设置
        */

        // 基础攻击力
        this.ATK_num = this.LV * 5;
        // 攻击力倍率
        this.ATK_promote = 1;

        // 基础防御力
        this.AC_num = this.LV * 2;
        // 防御力倍率
        this.AC_promote = 1;

        // 最大经验值为等级 * 1500
        this.full_EXP = this.LV * 1500;

        // 基础血量
        this.HP_num = this.LV * 500;
        // 基础法力值
        this.MP_num = this.LV * 300;

        // 基础暴击率
        this.CRI_num = this.LV * 1;
    }

    update () {
        // 每帧检测升级
        if (this.cur_EXP >= this.full_EXP) {
            // 升级
            this.upgrade();
        }


        // 每帧检测  防止穿帮

        // 如果当前血量小于0
        if (this.cur_HP < 0) {
            // 当前血量等于0
            this.cur_HP = 0;
        }

        // 如果当前大于满的血量
        if (this.cur_HP > this.full_HP) {
            // 当前血量等于满的血量
            this.cur_HP = this.full_HP;
        }


        // 如果当前魔法值小于0
        if (this.cur_MP < 0) {
            // 当前魔法值等于0
            this.cur_MP = 0;
        }


        // 如果当前魔法值大于满的魔法值
        if (this.cur_MP > this.full_MP) {
            // 当前魔法值等于满的魔法值
            this.cur_MP = this.full_MP;
        }




        // 如果是第一次执行update
        if (this.is_first_update == true) {
            // 不是第一次执行update了
            this.is_first_update = false;
            // 当前血量和魔法值等于满的血量和魔法值
            this.cur_HP = this.full_HP;
            this.cur_MP = this.full_MP;
        }



        // 显示在文字上
        // 血量
        this.HP_lb.string = "HP   " + Math.floor(this.cur_HP) + "/" + Math.floor(this.full_HP);
        // 魔法值
        this.MP_lb.string = "MP   " + Math.floor(this.cur_MP) + "/" + Math.floor(this.full_MP);
        // 经验值
        this.EXP_lb.string = "EXP   " + Math.floor(this.cur_EXP) + "/" + Math.floor(this.full_EXP);
        // 等级
        this.LV_lb.string = "LV:" + this.LV;

    

        // 进度也显示
        // 血量
        this.HP_sp.fillRange = this.cur_HP / this.full_HP;
        // 魔法值
        this.MP_sp.fillRange = this.cur_MP / this.full_MP;
        // 经验值
        this.EXP_sp.fillRange = this.cur_EXP / this.full_EXP;




        // 如果状态为静止
        if (this.state == State.idle) {
            // 打印log
            // cc.log("状态： 静止");

            // 如果动画不为静止
            if (this.player.animation != "idle") {
                // 动画为静止
                this.player.animation = "idle";
            }
            // 角色刚体线性速度X为0
            this.player.getComponent(cc.RigidBody).linearVelocity = cc.v2(0, this.player.getComponent(cc.RigidBody).linearVelocity.y);
        }
        // 如果状态为左走 
        else if (this.state == State.left) {
            // 打印log
            // cc.log("状态： 左走");

            // 如果动画不为走路
            if (this.player.animation != "walk") {
                // 动画为走路
                this.player.animation = "walk";
            }
            // 角色刚体线性速度X为向左的行走速度
            this.player.getComponent(cc.RigidBody).linearVelocity = cc.v2(-this.walk_speed, this.player.getComponent(cc.RigidBody).linearVelocity.y);
            // 人物缩放
            this.player.node.scaleX = -0.6;
        }
        // 如果状态为右走 
        else if (this.state == State.right) {
            // 打印log
            // cc.log("状态： 右走");

            // 如果动画不为走路
            if (this.player.animation != "walk") {
                // 动画为走路
                this.player.animation = "walk";
            }
            // 角色刚体线性速度X为向右的行走速度
            this.player.getComponent(cc.RigidBody).linearVelocity = cc.v2(this.walk_speed, this.player.getComponent(cc.RigidBody).linearVelocity.y);
            // 人物缩放
            this.player.node.scaleX = 0.6;
        } 
        // 如果状态为攻击
        else if (this.state == State.atttack) {
            // 打印log
            // cc.log("状态： 攻击");
        }
        // 如果状态为跳跃
        else if (this.state == State.jump) {
            // 打印log
            // cc.log("状态： 跳跃");
        }
        // 如果状态为受伤
        else if (this.state == State.injured) {
            let self = this;

            // 如果动画不是受伤
            if (this.player.animation != "injured") {
                // 动画为受伤
                this.player.animation = "injured";
            }

            // 当动画播放完成后
            this.player.setCompleteListener(function () {
                // 如果状态为受伤
                if (self.state == State.injured) {
                    // 状态为idle
                    self.state = State.idle;
                    // 清空管道
                    self.player.clearTracks();
                }
            });
        }

    }

    // 左走专用函数
    left_walk () {
        this.state = State.left;
    }

    // 右走专用函数
    right_walk () {
        this.state = State.right;
    }

    // 静止专用函数
    idle_walk () {
        this.state = State.idle;
    }

    // 跳跃专用函数
    jump () {
        // 如果可以跳跃
        if (this.is_jump_OK == true) {
            // this.jump_btn.getComponent(cc.Button).interactable = false;
            let self = this;
            // 状态为跳跃
            this.state = State.jump;
            // 不可跳跃
            self.is_jump_OK = false;
            // 动画为空
            this.player.animation = null;
            // 清理管道
            this.player.clearTracks();
            // 设置线速度
            this.player.getComponent(cc.RigidBody).linearVelocity = cc.v2(this.player.getComponent(cc.RigidBody).linearVelocity.x, this.jump_height);
            // 添加动画  0号管道 跳跃动画 不循环播放 0秒延迟
            this.player.addAnimation(0, "jump", false, 0);
            // 在动画结束后
            this.player.setCompleteListener(function () {
                // 如果状态为跳跃
                if (self.state == State.jump) {
                    // 状态变为idle
                    self.state = State.idle;
                    // 清理管道
                    self.player.clearTracks();
                }
            });

            /* // 在规定的时间后恢复禁用
            this.scheduleOnce(function () {
                // self.jump_btn.getComponent(cc.Button).interactable = true;

                // self.is_jump_OK = true;
            }, this.jump_time); */

        }
    }

    // 攻击函数
    attack () {
        // 如果可以攻击
        if (this.is_attack_OK == true) {
            let self = this;
            // 不可攻击
            this.is_attack_OK = false;
            // 状态为攻击
            this.state = State.atttack;
            // 在规定的时间后恢复禁用
            this.scheduleOnce(function () {
                self.is_attack_OK = true;
            }, this.attack_time);



            // 如果攻击数字为1
            if (this.attack_num == 1) {
                // 攻击数字为2
                this.attack_num = 2;
                // 动画为空
                this.player.animation = null;
                // 清空管道
                this.player.clearTracks();
                // 添加动画 0号管道 攻击动画1 不循环 0秒延迟
                this.player.addAnimation(0, "attack1", false, 0);
                // 在动画播放完后
                this.player.setCompleteListener(function () {
                    // 如果状态为攻击
                    if (self.state == State.atttack) {
                        // 状态为idle
                        self.state = State.idle;
                        // 清空管道
                        self.player.clearTracks();
                    }
                });
                // 打印log
                cc.log("攻击1");
                // 以下代码不执行

                this.open_attack_right(this.attack_range_time);


                // 以下代码不执行
                return;
            }



            // 如果攻击数字为2
            if (this.attack_num == 2) {
                // 攻击数字为3
                this.attack_num = 3;
                // 动画为空
                this.player.animation = null;
                // 清空管道
                this.player.clearTracks();
                // 添加动画 0号管道 攻击动画2 不循环 0秒延迟
                this.player.addAnimation(0, "attack2", false, 0);
                // 在动画播放完成后
                this.player.setCompleteListener(function () {
                    // 如果状态为攻击
                    if (self.state == State.atttack) {
                        // 状态为idle
                        self.state = State.idle;
                        // 清空管道
                        self.player.clearTracks();
                    }
                });
                // 打印log
                cc.log("攻击2");

                this.open_attack_right(this.attack_range_time);


                // 以下代码不执行
                return;
            }



            // 如果攻击数字为3
            if (this.attack_num == 3) {
                // 攻击数字为1
                this.attack_num = 1;
                // 动画为空
                this.player.animation = null;
                // 清空管道
                this.player.clearTracks();
                // 添加动画 0号管道 攻击动画3 不循环 0秒延迟
                this.player.addAnimation(0, "attack3", false, 0);
                // 在动画播放完成后
                this.player.setCompleteListener(function () {
                    // 如果状态为攻击
                    if (self.state == State.atttack) {
                        // 状态为idle
                        self.state = State.idle;
                        // 清空管道
                        self.player.clearTracks();
                    }
                });
                // 打印log
                cc.log("攻击3");

             
                // 左右攻击范围都打开
                this.open_attack_right(this.attack_range_time);
                this.open_attack_left(this.attack_range_time);
                cc.log("左右都打开了");


                // 以下代码不执行
                return;
            }
        }
    }


    // 左攻击范围打开，num为几秒后恢复
    open_attack_left (num: number) {
        let self = this;
        // 打开左攻击范围
        this.attack_left.active = true;
        // 规定时间后恢复
        this.scheduleOnce(function () {
            self.attack_left.active = false;
        }, num);
    }


    // 右攻击范围打开，num为几秒后恢复
    open_attack_right (num: number) {
        let self = this;
        // 打开右攻击范围
        this.attack_right.active = true;
        // 规定时间后恢复
        this.scheduleOnce(function () {
            self.attack_right.active = false;
        }, num);
    }


    // 碰撞回调
    // 当碰撞产生的时候调用   other 产生碰撞的另一个碰撞组件self  产生碰撞的自身的碰撞组件
    onCollisionEnter (other, self) {
        // 如果被敌人打到了
        if (other.node.group == "foe_attack") {
            // 打印log
            cc.log("人物受到了伤害，伤害来源：" + other.node.name);
            // 状态为受伤
            this.state = State.injured;

            // 敌人攻击力为敌人攻击力 - 自身防御力
            let ATK = Math.floor((other.node.parent.getComponent("Foe").ATK_num_F) - this.AC);
            // 如果结果小于等于0
            if (ATK <= 0) {
                // 攻击力为1
                ATK = 1;
            }
            // 减少血量
            this.reduce_HP(ATK);
            // 创建新的文字
            this.new_num(ATK);
        }
    }


    // 减少生命值函数，num为减少的数值
    reduce_HP (num: number) {
        // 减少生命
        this.cur_HP -= num;
    }

    
    // 减少法力值专用函数，num为减少的数值
    reduce_MP (num: number) {
        // 减少魔法值
        this.cur_MP -= num;
    }


    // 回血专用函数，num为恢复的数值
    add_HP (num: number) {
        // 回血
        this.cur_HP += num;
    }


    // 回蓝专用函数，num为恢复的数值
    add_MP (num: number) {
        // 回蓝
        this.cur_MP += num;
    }



    // 创建新的伤害数字函数，num为数字的值
    new_num (num: number) {
        // 创建新的节点
        let node = new cc.Node;
        // 添加label
        node.addComponent(cc.Label);

        // 获取label
        let lb = node.getComponent(cc.Label);
        // 显示内容
        lb.string = Math.floor(num).toString();
        // 设置字体
        lb.font = this.purple_typeface;

        // 父节点为canvas
        node.parent = this.canvas;
        // 设置坐标
        node.x = this.player.node.x;
        node.y = this.player.node.y + (this.player.node.height / 2) + 30;

        // 移动动作
        let move = cc.moveBy(2, cc.v2(0, 100));
        // 回调函数
        let func = cc.callFunc(function () {
            node.destroy();
        }, this);
        // 两个结合在一起
        let action = cc.sequence(move, func);
        // 执行动作
        node.runAction(action);
    }


    // 死亡专用函数
    death () {
        // 角色透明度为0
        this.player.node.opacity = 0;
        // 分组为默认
        this.player.node.group = "default";

        // for循环隐藏UI
        for (let i = 0; i < this.UI.length; i ++) {            
            this.UI[i].active = false;
        }

        // for循环隐藏技能按钮
        for (let i = 0; i < this.UI_skill_btn.length; i ++) {            
            this.UI_skill_btn[i].interactable = false;
        }

        // 显示复活界面
        this.UI_death.active = true;

        // 存储数据
        this.save_user_data();
    }


    // 复活专用函数
    resurgence () {
        // 恢复角色透明度
        this.player.node.opacity = 255;
        // 分组为player
        this.player.node.group = "player";
        // 当前血量为满的血量
        this.cur_HP = this.full_HP;

        // for循环显示按钮
        for (let i = 0; i < this.UI.length; i ++) {            
            this.UI[i].active = true;
        }

        // for循环显示技能按钮
        for (let i = 0; i < this.UI_skill_btn.length; i ++) {            
            this.UI_skill_btn[i].interactable = true;
        }

        // 隐藏复活界面
        this.UI_death.active = false;

        // 因为只可以复活一次，所以隐藏复活按钮
        this.re_btn.active = false;
    }


    // 增加经验值专用函数   num为增加多少
    add_EXP (num: number) {
        this.cur_EXP += num;
    }

    
    // 人物升级专用函数
    upgrade () {
        // this.LV = Number(this.user_data.LV);
        // this.cur_EXP = Number(this.user_data.EXP);

        // 等级 + 1
        this.LV += 1;
        // 当前经验值为0
        this.cur_EXP = 0;


        // 两个结合在一起
        let user_data = {
            LV: this.LV,
            EXP: 0,
        }


        // 存起来
        cc.sys.localStorage.setItem("user_data", JSON.stringify(user_data));

        

        /*
        以下代码为各种属性普通值和倍率值的设置
        */

        // 基础攻击力
        this.ATK_num = this.LV * 5;
        // 攻击力倍率
        this.ATK_promote = 1;

        // 基础防御力
        this.AC_num = this.LV * 2;
        // 防御力倍率
        this.AC_promote = 1;

        // 最大经验值为等级 * 1500
        this.full_EXP = this.LV * 1500;

        // 基础血量
        this.HP_num = this.LV * 500;
        // 基础法力值
        this.MP_num = this.LV * 300;

        // 基础暴击率
        this.CRI_num = this.LV * 1;

        // 当前血量为满的血量
        this.cur_HP = this.full_HP;
        // 当前魔法值为满的魔法值
        this.cur_MP = this.full_MP;
    }



    // 存储用户数据
    save_user_data () {
        // 获取用户数据
        let user_data = {
            LV: this.LV,
            EXP: this.cur_EXP,
        }

        // 存起来
        cc.sys.localStorage.setItem("user_data", JSON.stringify(user_data));
    }


    // 物理碰撞回调
    onBeginContact (contact/*碰撞*/:cc.PhysicsContact,selfCollider/*被碰撞*/:cc.PhysicsCollider,otherConllider/*另一个碰撞体*/:cc.PhysicsCollider): void {
        console.log("角色到达了地面，启用按钮");

        // 可以跳跃了
        this.is_jump_OK = true;
        // 只在两个碰撞体开始接触时调用一次
    }





}
